package com.xiaomaoguai.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipInputStream;


/**
 * Activiti 流程定义测试,流程部署--流程查询--流程删除
 *
 * @ ClassName: ProcessDefinitionTest.java
 * @ Author: WeiHui-Z
 * @ Date: 2016/12/10 15:37
 * @ Version: v1.0.0
 */
public class ProcessDefinitionTest {

	private static final Logger LOGGER = LoggerFactory.getLogger(ProcessDefinitionTest.class);

	private ProcessEngine processEngine;

	@Before
	public void setUp() {
		processEngine = ProcessEngines.getDefaultProcessEngine();
	}

	/**
	 * 流程部署一(从classpath)
	 */
	@Test
	public void deployOne() {
		RepositoryService repositoryService = processEngine.getRepositoryService();

		Deployment deploy = repositoryService.createDeployment().name("Hard流程").//
				addClasspathResource("diagrams/processVariables.bpmn").//
				addClasspathResource("diagrams/processVariables.png").//
				deploy();

		LOGGER.info("流程部署:{},{}", deploy.getId(), deploy.getName());
	}

	/**
	 * 流程部署一(从classpath)
	 * <pre>
	 * 执行的SQL顺序： 4条插入
	 *
	 *  1.insert into ACT_RE_PROCDEF(ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_, RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_, HAS_GRAPHICAL_NOTATION_ , SUSPENSION_STATE_, TENANT_ID_)
	 *  values ('NCIIC_AUTO:1:22504', 1, 'http://www.activiti.org/test', '简易流程', 'NCIIC_AUTO', 1, '22501', 'NCIIC_AUTO.bpmn', 'NCIIC_AUTO.png', null, false, true, 1, '')
	 *
	 *  2.insert into ACT_RE_DEPLOYMENT(ID_, NAME_, CATEGORY_, TENANT_ID_, DEPLOY_TIME_)
	 *  values('22501', 'Hard流程', null, '', '2016-12-14 18:20:33.085')
	 *
	 *  3.INSERT INTO ACT_GE_BYTEARRAY(ID_, REV_, NAME_, BYTES_, DEPLOYMENT_ID_, GENERATED_)
	 *  VALUES ('22502', 1, 'NCIIC_AUTO.bpmn', 'java.io.ByteArrayInputStream@30d25c03', '22501', false) ,
	 *  ('22503', 1, 'NCIIC_AUTO.png', 'java.io.ByteArrayInputStream@7a1f8def', '22501', false)
	 * /pre>
	 */
	@Test
	public void deployZip() {
		RepositoryService repositoryService = processEngine.getRepositoryService();

		InputStream in = this.getClass().getClassLoader().getResourceAsStream("diagrams/NCIIC_AUTO.zip");
		Deployment deploy = repositoryService.createDeployment().name("NCIIC_AUTO简易流程").//
				addZipInputStream(new ZipInputStream(in)).//
				deploy();

		LOGGER.info("流程部署:{},{}", deploy.getId(), deploy.getName());
	}

	/**
	 * 查询部署的流程定义-并得到流程的所有节点信息
	 *
	 *  select * from ACT_RE_PROCDEF where DEPLOYMENT_ID_ = '22501' and KEY_ = 'NCIIC_AUTO' and (TENANT_ID_ = '' or TENANT_ID_ is null)
	 */
	@Test
	public void queryDeployProcessDefinition() {
		String deploymentId = "22501";
		RepositoryService repositoryService = processEngine.getRepositoryService();
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).latestVersion().singleResult();
		LOGGER.info("流程定义:{}", processDefinition);
		LOGGER.info("流程定义Id:{},name:{},key:{},是否挂起：{}", processDefinition.getId(), processDefinition.getName(), processDefinition.getKey(), processDefinition.isSuspended());

		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(processDefinition.getId());
		//得到流程图的所有节点--包括开始，结束节点
		List<ActivityImpl> activityList = processDefinitionEntity.getActivities();
		List<ActivityImpl> nodeList = new ArrayList<>(activityList.size() - 2);
		for (ActivityImpl node : activityList) {
			LOGGER.info("{}", node.getProperties());
			//过滤 startEvent endEvent
			if ("userTask".equals(node.getProperty("type"))) {
				nodeList.add(node);
			}
		}

		//得到去掉开始和 结束的节点，保存到数据库，为每一个节点动态安排--人
		for (ActivityImpl activity : nodeList) {
			LOGGER.info("{}", activity.getProperties());
		}
	}

	/**
	 * 删除部署资源
	 *  1.select * from ACT_RE_DEPLOYMENT where ID_ = '12501'
	 *  2.select distinct RES.* from ACT_RE_PROCDEF RES WHERE RES.DEPLOYMENT_ID_ = '12501' order by RES.ID_ asc LIMIT 2147483647 OFFSET 0
	 *  3.select distinct RES.* from ACT_RE_MODEL RES WHERE RES.DEPLOYMENT_ID_ = '12501' order by RES.ID_ asc LIMIT 2147483647 OFFSET 0
	 *  4.select ID_ from ACT_RU_EXECUTION where PROC_DEF_ID_ = 'processVariables:1:12504' and PARENT_ID_ is null
	 *  5.select * from ACT_RU_EXECUTION where ID_ = '15001'
	 *  6.select distinct RES.* , P.KEY_ as ProcessDefinitionKey, P.ID_ as ProcessDefinitionId, P.NAME_ as ProcessDefinitionName, P.VERSION_ as ProcessDefinitionVersion, P.DEPLOYMENT_ID_ as DeploymentId from ACT_RU_EXECUTION RES inner join ACT_RE_PROCDEF P on RES.PROC_DEF_ID_ = P.ID_ WHERE RES.PARENT_ID_ is null and RES.SUPER_EXEC_ IN (select ID_ from ACT_RU_EXECUTION where PROC_INST_ID_ = '15001') order by RES.ID_ asc LIMIT 2147483647 OFFSET 0
	 *  7.select distinct RES.* from ACT_RU_TASK RES WHERE RES.PROC_INST_ID_ = '15001' order by RES.ID_ asc LIMIT 2147483647 OFFSET 0
	 *  8.select * from ACT_RE_PROCDEF where ID_ = 'processVariables:1:12504'
	 *  9.select * from ACT_GE_BYTEARRAY where DEPLOYMENT_ID_ = '12501' order by NAME_ asc
	 *  10.select * from ACT_RE_PROCDEF where DEPLOYMENT_ID_ = '12501' and KEY_ = 'processVariables' and (TENANT_ID_ = '' or TENANT_ID_ is null)
	 *  11.select * from ACT_RU_TASK where PARENT_TASK_ID_ = '15007'
	 *  12.select * from ACT_RU_IDENTITYLINK where TASK_ID_ = '15007'
	 *  13.select * from ACT_RU_VARIABLE where TASK_ID_ = '15007'
	 *  14.select * from ACT_HI_TASKINST where ID_ = '15007'
	 *  15.select * from ACT_HI_TASKINST where PARENT_TASK_ID_ = '15007'
	 *  16.select RES.* from ACT_HI_VARINST RES WHERE RES.TASK_ID_ = '15007' order by RES.ID_ asc LIMIT 2147483647 OFFSET 0
	 *  17.select * from ACT_HI_ATTACHMENT where TASK_ID_ = '15007' order by TIME_ desc
	 *  18.select * from ACT_HI_IDENTITYLINK where TASK_ID_ = '15007'
	 *  18.select * from ACT_RU_EXECUTION where PARENT_ID_ = '15001'
	 *  19.select * from ACT_RU_EXECUTION where SUPER_EXEC_ = '15001'
	 *  19.select RES.* from ACT_HI_ACTINST RES WHERE RES.EXECUTION_ID_ = '15001' and RES.ACT_ID_ = 'usertask1' and RES.END_TIME_ is null order by RES.ID_ asc LIMIT 1 OFFSET 0
	 *  19.select * from ACT_HI_PROCINST where PROC_INST_ID_ = '15001'
	 *  20.select * from ACT_RU_VARIABLE where EXECUTION_ID_ = '15001' and TASK_ID_ is null
	 *  21.select * from ACT_HI_VARINST where ID_ = '15003'
	 *
	 */
	@Test
	public void deleteDeploy() {
		RepositoryService repositoryService = processEngine.getRepositoryService();
		repositoryService.deleteDeployment("12501", true);
	}

	/**
	 * 流程部署二(从zip文件)
	 * <p>
	 * 操作了3张表
	 * </p>
	 * act_re_deployment---部署名称以及Id和部署时间</br>
	 * act_ge_bytearray--关联部署的Id以及保存流程文件为2进制数据</br>
	 * act_re_procdef</br>
	 *
	 * @author: WeiHui.Zhang
	 * @date: 2016年8月2日 上午10:07:59
	 * @Version: V1.00
	 * @Title: deployTwo void
	 */
	@Test
	public void deployTwo() throws Exception {
		RepositoryService repositoryService = processEngine.getRepositoryService(); // 与流程部署定义相关的service

		InputStream in = this.getClass().getClassLoader().getResourceAsStream("diagrams/helloworld.zip");
		ZipInputStream zipInputStream = new ZipInputStream(in);
		Deployment deploy = repositoryService.createDeployment().name("TEST-2流程").//
				addZipInputStream(zipInputStream).deploy();

		LOGGER.info("流程部署:{},{}", deploy.getId(), deploy.getName());
	}

	/**
	 * 查询流程定义
	 *
	 * @author: WeiHui.Zhang
	 * @date: 2016年8月3日 上午11:20:55
	 * @Version: V1.00
	 * @Title: findprocessDefinition void
	 */
	@Test
	public void findprocessDefinition() {
		RepositoryService repositoryService = processEngine.getRepositoryService();

		DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery();
		List<Deployment> deployments = deploymentQuery.list();

		for (Deployment deployment : deployments) {
			System.out.println(deployment.getName());
		}

		// 创建一个流程定义的查询
		ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
		/** 指定查询条件,where条件 */
		// .deploymentId(deploymentId)//使用部署对象ID查询
		// .processDefinitionId(processDefinitionId)//使用流程定义ID查询
		// .processDefinitionKey(processDefinitionKey)//使用流程定义的key查询
		// .processDefinitionNameLike(processDefinitionNameLike)//使用流程定义的名称模糊查询
		List<ProcessDefinition> processDefinitions = processDefinitionQuery.list();

		if (processDefinitions != null && !processDefinitions.isEmpty()) {
			for (ProcessDefinition pd : processDefinitions) {
				System.out.println("流程定义ID:" + pd.getId());// 流程定义的key+版本+随机生成数
				System.out.println("流程定义的名称:" + pd.getName());// 对应helloworld.bpmn文件中的name属性值
				System.out.println("流程定义的key:" + pd.getKey());// 对应helloworld.bpmn文件中的id属性值
				System.out.println("流程定义的版本:" + pd.getVersion());// 当流程定义的key值相同的相同下，版本升级，默认1
				System.out.println("资源名称bpmn文件:" + pd.getResourceName());
				System.out.println("资源名称png文件:" + pd.getDiagramResourceName());
				System.out.println("部署对象ID：" + pd.getDeploymentId());
				System.out.println("#########################################################");
			}
		}
	}

	/**
	 * 删除流程定义
	 *
	 * @author: WeiHui.Zhang
	 * @date: 2016年8月3日 上午11:24:47
	 * @Version: V1.00
	 * @Title: deleteProcessDefinition void
	 */
	@Test
	public void deleteProcessDefinition() {
		RepositoryService repositoryService = processEngine.getRepositoryService();
		String deploymentId = "25001";
		// 级联删除
		repositoryService.deleteDeployment(deploymentId, true);
	}

	/**
	 * 查看流程图
	 *
	 * @throws Exception void
	 * @author: WeiHui.Zhang
	 * @date: 2016年8月3日 下午2:08:55
	 * @Version: V1.00
	 * @Title: viewProcessImg
	 */
	@Test
	public void viewProcessImg() throws Exception {
		RepositoryService repositoryService = processEngine.getRepositoryService();
		String deploymentId = "1";
		List<String> list = repositoryService.getDeploymentResourceNames(deploymentId);

		String resourceName = "";
		if (list != null && !list.isEmpty()) {
			for (String string : list) {
				if (string.contains("png")) {
					resourceName = string;
				}
			}
		}
		InputStream in = repositoryService.getResourceAsStream(deploymentId, resourceName);

		File file = new File("f:/1.png");
		byte[] by = FileCopyUtils.copyToByteArray(in);
		FileCopyUtils.copy(by, file);
	}
}
